package com.kuaiyin.util;

import com.kuaiyin.dto.JMeterTestDTO;
import com.kuaiyin.dto.JMeterTestDTO.HttpRequestConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.config.gui.ArgumentsPanel;
import org.apache.jmeter.control.LoopController;
import org.apache.jmeter.control.TransactionController;
import org.apache.jmeter.control.gui.LoopControlPanel;
import org.apache.jmeter.control.gui.TestPlanGui;
import org.apache.jmeter.control.gui.TransactionControllerGui;
import org.apache.jmeter.extractor.json.jsonpath.JSONPostProcessor;
import org.apache.jmeter.extractor.json.jsonpath.gui.JSONPostProcessorGui;
import org.apache.jmeter.protocol.http.control.Header;
import org.apache.jmeter.protocol.http.control.HeaderManager;
import org.apache.jmeter.protocol.http.control.gui.HttpTestSampleGui;
import org.apache.jmeter.protocol.http.gui.HeaderPanel;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
import org.apache.jmeter.protocol.http.util.HTTPArgument;
import org.apache.jmeter.reporters.ResultCollector;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.testelement.TestPlan;
import org.apache.jmeter.threads.ThreadGroup;
import org.apache.jmeter.threads.gui.ThreadGroupGui;
import org.apache.jorphan.collections.HashTree;
import org.springframework.util.StringUtils;

import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class JMeterTestBuilder {

    public static String buildAndSaveJmx(JMeterTestDTO dto) throws Exception {
        if (dto == null) throw new IllegalArgumentException("DTO对象不能为空");

        JmeterUtil.initJmeterProperties();

        TestPlan testPlan = new TestPlan(dto.getName() != null ? dto.getName() : "默认测试计划");
        testPlan.setProperty(TestElement.GUI_CLASS, TestPlanGui.class.getName());
        testPlan.setProperty(TestElement.TEST_CLASS, TestPlan.class.getName());
        testPlan.setProperty(TestPlan.COMMENTS, dto.getComment() != null ? dto.getComment() : "");

        Arguments userVars = new Arguments();
        userVars.setProperty(TestElement.GUI_CLASS, ArgumentsPanel.class.getName());
        userVars.setProperty(TestElement.TEST_CLASS, Arguments.class.getName());
        testPlan.setUserDefinedVariables(userVars);

        JMeterTestDTO.ThreadGroupConfig threadGroupConfig = dto.getThreadGroup();
        if (threadGroupConfig == null) throw new IllegalArgumentException("线程组配置不能为空");

        boolean isSchedulerEnabled = threadGroupConfig.isScheduler() && threadGroupConfig.getLoops() == -1;

        LoopController loopController = new LoopController();
        loopController.setLoops(threadGroupConfig.getLoops());
        loopController.setFirst(true);
        loopController.initialize();
        loopController.setProperty(TestElement.GUI_CLASS, LoopControlPanel.class.getName());
        loopController.setProperty(TestElement.TEST_CLASS, LoopController.class.getName());

        ThreadGroup threadGroup = new ThreadGroup();
        threadGroup.setName(threadGroupConfig.getName() != null ? threadGroupConfig.getName() : "线程组");
        threadGroup.setNumThreads(threadGroupConfig.getThreads());
        threadGroup.setRampUp(threadGroupConfig.getRampUp());
        threadGroup.setSamplerController(loopController);
        threadGroup.setProperty(TestElement.GUI_CLASS, ThreadGroupGui.class.getName());
        threadGroup.setProperty(TestElement.TEST_CLASS, ThreadGroup.class.getName());

        if (isSchedulerEnabled) {
            threadGroup.setScheduler(true);
            if (threadGroupConfig.getDuration() > 0) {
                threadGroup.setDelay(threadGroupConfig.getDelayedStart());
                threadGroup.setDuration(threadGroupConfig.getDuration());
            }
        } else {
            threadGroup.setScheduler(false);
        }

        // === 构建测试计划树 ===
        HashTree testPlanTree = new HashTree();
        HashTree threadGroupTree = testPlanTree.add(testPlan).add(threadGroup);

        List<JMeterTestDTO.HttpRequestConfig> requests = dto.getHttpRequests();
        if (requests != null && !requests.isEmpty()) {
            if (requests.size() > 1) {
                TransactionController transactionController = new TransactionController();
                transactionController.setName("事务控制器");
                transactionController.setGenerateParentSample(true);
                transactionController.setIncludeTimers(false);
                transactionController.setProperty(TestElement.GUI_CLASS, TransactionControllerGui.class.getName());
                transactionController.setProperty(TestElement.TEST_CLASS, TransactionController.class.getName());

                HashTree transactionTree = threadGroupTree.add(transactionController);

                for (JMeterTestDTO.HttpRequestConfig request : requests) {
                    addHttpRequestToTree(transactionTree, request);
                }
            } else {
                addHttpRequestToTree(threadGroupTree, requests.get(0));
            }
        }
//        addAggregateReportListener(threadGroupTree);
        // === 序列化到内存并返回 String ===
        try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
            SaveService.saveTree(testPlanTree, out);
            return out.toString(StandardCharsets.UTF_8);
        }

    }


    private static void addAggregateReportListener(HashTree threadGroupTree) {
        ResultCollector resultCollector = new ResultCollector();
        resultCollector.setName("聚合报告");

        // 改这里：使用 JMeter 内置的聚合报告 GUI 类
        resultCollector.setProperty(TestElement.GUI_CLASS, "StatVisualizer");
        resultCollector.setProperty(TestElement.TEST_CLASS, ResultCollector.class.getName());

        // filename 必须设置，即使为空字符串，防止 GUI 加载 NPE
        resultCollector.setProperty("filename", "");

        resultCollector.setEnabled(true);

        threadGroupTree.add(resultCollector);
    }




    private static void addHttpRequestToTree(HashTree parentTree, HttpRequestConfig request) {
        HTTPSamplerProxy httpSampler = buildHttpSampler(request);
        HeaderManager headerManager = buildHeaderManager(request);
        JSONPostProcessor jsonExtractor = buildJsonExtractor(request);
        HashTree samplerTree = parentTree.add(httpSampler);
        samplerTree.add(headerManager);
        if (jsonExtractor != null) {
            samplerTree.add(jsonExtractor);
        }
    }

    private static HTTPSamplerProxy buildHttpSampler(HttpRequestConfig request) {
        HTTPSamplerProxy httpSampler = new HTTPSamplerProxy();

        httpSampler.setDomain(request.getDomain() != null ? request.getDomain() : "localhost");
        httpSampler.setPort(request.getPort());
        httpSampler.setProtocol(request.getProtocol() != null ? request.getProtocol() : "http");
        httpSampler.setPath(request.getPath() != null ? request.getPath() : "/");
        httpSampler.setMethod(request.getMethod() != null ? request.getMethod().toUpperCase() : "GET");
        httpSampler.setName(request.getName() != null ? request.getName() : "请求");
        httpSampler.setFollowRedirects(request.isFollowRedirects());
        httpSampler.setUseKeepAlive(request.isKeepAlive());
        httpSampler.setProperty(TestElement.GUI_CLASS, HttpTestSampleGui.class.getName());
        httpSampler.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());

        String method = httpSampler.getMethod().toUpperCase();

        if (request.getBody() != null && !request.getBody().isEmpty()
                && ("POST".equals(method) || "PUT".equals(method) || "PATCH".equals(method) || "DELETE".equals(method))) {

            if (request.getHeaders() == null) {
                request.setHeaders(new HashMap<>());
            }
            request.getHeaders().putIfAbsent("Content-Type", "application/json");

            String jsonBody = com.alibaba.fastjson.JSON.toJSONString(request.getBody());
            httpSampler.addNonEncodedArgument("", jsonBody, "");
            httpSampler.setPostBodyRaw(true);
        } else if (request.getParameters() != null && !request.getParameters().isEmpty()) {
            Arguments arguments = new Arguments();
            arguments.setProperty(TestElement.GUI_CLASS, ArgumentsPanel.class.getName());
            arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName());

            for (Map.Entry<String, String> entry : request.getParameters().entrySet()) {
                HTTPArgument httpArg = new HTTPArgument(entry.getKey(), entry.getValue());
                httpArg.setAlwaysEncoded(false);
                arguments.addArgument(httpArg);
            }

            httpSampler.setArguments(arguments);
        }

        return httpSampler;
    }

    private static HeaderManager buildHeaderManager(HttpRequestConfig request) {
        HeaderManager headerManager = new HeaderManager();
        headerManager.setName("请求头管理器");
        headerManager.setProperty(TestElement.GUI_CLASS, HeaderPanel.class.getName());
        headerManager.setProperty(TestElement.TEST_CLASS, HeaderManager.class.getName());
        if (request.getHeaders() != null) {
            for (Map.Entry<String, String> entry : request.getHeaders().entrySet()) {
                headerManager.add(new Header(entry.getKey(), entry.getValue()));
            }
        }
        return headerManager;
    }

    private static JSONPostProcessor buildJsonExtractor(HttpRequestConfig request) {
        Map<String, Object> extractMap = request.getExtractVariables();
        if (extractMap == null || extractMap.isEmpty()) return null;

        JSONPostProcessor jsonExtractor = new JSONPostProcessor();
        jsonExtractor.setName("JSON提取器");
        jsonExtractor.setEnabled(true);
        jsonExtractor.setProperty(TestElement.GUI_CLASS, JSONPostProcessorGui.class.getName());
        jsonExtractor.setProperty(TestElement.TEST_CLASS, JSONPostProcessor.class.getName());

        List<String> varNames = new ArrayList<>();
        List<String> jsonPaths = new ArrayList<>();
        List<String> defaults = new ArrayList<>();
        List<String> matchNumbers = new ArrayList<>();

        for (Map.Entry<String, Object> entry : extractMap.entrySet()) {
            String varName = entry.getKey();
            String jsonPath = String.valueOf(entry.getValue()).trim();

            if (!StringUtils.hasText(varName) || !StringUtils.hasText(jsonPath)) {
                continue;
            }

            varNames.add(varName);
            jsonPaths.add(jsonPath);
            defaults.add("NOT_FOUND"); // 设置默认值，避免未命中时抛异常
            matchNumbers.add("1"); // 默认取第一个
        }

        if (varNames.isEmpty()) return null;

        jsonExtractor.setProperty("JSONPostProcessor.referenceNames", String.join(";", varNames));
        jsonExtractor.setProperty("JSONPostProcessor.jsonPathExprs", String.join(";", jsonPaths));
        jsonExtractor.setProperty("JSONPostProcessor.defaultValues", String.join(";", defaults));
        jsonExtractor.setProperty("JSONPostProcessor.match_numbers", String.join(";", matchNumbers));

        return jsonExtractor;
    }


}
